package com.analyse.stock.vo;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import com.analyse.stock.constant.StockConstant;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.ta4j.core.Bar;
import org.ta4j.core.num.Num;

import java.io.Serializable;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.Objects;

@Slf4j
@Data
public class StockPositionVO implements Serializable {

    //股票code
    private String stockCode;

    //股票数量
    private Integer number;

    //平均持仓成本
    private BigDecimal avgPrice;

    //买入花费金额
    private BigDecimal amt;

    //开仓日期
    public String openDate;

    //当前盈亏比率
    private BigDecimal profitLostPercent;

    //最大涨幅
    private BigDecimal maxProfitLossPercent;

    //当前已下买单次数
    public int currentBuyTimes;

    //最大买单次数
    public int maxBuyTimes;

    //止盈5%
    private BigDecimal winPercent = new BigDecimal("6");
    //止损-3%
    private BigDecimal lossPercent = new BigDecimal("-4");

    //上一次开仓时间
    private String lastCreatePositDate;

    //间隔时间N天，下一次最早N天后
    private int intervalDay = 3;

    public StockPositionVO(){}
    public StockPositionVO(String stockCode,Integer number,BigDecimal amt,BigDecimal avgPrice,String openDate){
        this.stockCode = stockCode;
        this.number = number;
        this.amt = amt;
        this.avgPrice = avgPrice;
        this.openDate = openDate;
    }

    public static StockPositionVO buy(String stockCode,BigDecimal onceAmt,StockPositionVO positionVO,Bar bar){
        if(Objects.isNull(positionVO)){
            positionVO = new StockPositionVO(stockCode,0,BigDecimal.ZERO,BigDecimal.ZERO,"");
            positionVO.setMaxBuyTimes(3);
            positionVO.setCurrentBuyTimes(0);
            positionVO.setIntervalDay(3);
        }
        LocalDateTime date = bar.getEndTime().toLocalDateTime();
        String dateStr = DateUtil.format(date, DatePattern.NORM_DATE_FORMAT.getPattern());
        positionVO.setLastCreatePositDate(dateStr);
        if(positionVO.getCurrentBuyTimes()>=positionVO.getMaxBuyTimes()){
            log.error("## 【买入达到上限】，取消下单，日期：{}，股票：{}",
                    dateStr,positionVO.getStockCode());
            return positionVO;
        }
        if(CollUtil.isNotEmpty(StockConstant.historyTradMap) && StockConstant.historyTradMap.containsKey(stockCode)){
            String hisDate = StockConstant.historyTradMap.get(stockCode).getLastCreatePositDate();
            int day = StockConstant.historyTradMap.get(stockCode).getIntervalDay();
            Date offDay = DateUtil.offsetDay(DateUtil.parseDate(hisDate),day);
            Date tradingDate =  DateUtil.parseDate(dateStr);
            // n天后 是大于当前日期的，不开单
            if(tradingDate.before(offDay)){
                log.error("## 股票：{}, 【{}】后才能开单，需要间隔：{} 天，取消下单......",
                        positionVO.getStockCode(),DateUtil.format(offDay,DatePattern.NORM_DATE_FORMAT),day);
                return positionVO;
            }
        }

        Num price = bar.getClosePrice();
        BigDecimal hand = onceAmt.divide(BigDecimal.valueOf(price.doubleValue()*100),2, RoundingMode.HALF_UP);
        int handMax = hand.intValue();
        //总花费多少
        BigDecimal amt = positionVO.getAmt().add(BigDecimal.valueOf(price.doubleValue()).multiply(new BigDecimal(handMax*100)));
        int stockNumber = (handMax *100) + positionVO.getNumber();
        BigDecimal avgPrice = amt.divide(BigDecimal.valueOf(stockNumber),2,RoundingMode.HALF_UP);

        positionVO.setNumber(stockNumber);
        positionVO.setAvgPrice(avgPrice);
        positionVO.setAmt(amt);
        positionVO.setCurrentBuyTimes( positionVO.getCurrentBuyTimes()+1);

        if(StringUtils.isBlank(positionVO.getOpenDate())){
            positionVO.setOpenDate(dateStr);
        }
        positionVO.setProfitLostPercent(BigDecimal.ZERO);
        positionVO.setMaxProfitLossPercent(BigDecimal.ZERO);
        log.info("## 【买入】日期：{}，股票：{}，买入价格：{}，持仓平均价格：{}, 总持仓市值：{}，持仓股票数量：{}",dateStr,positionVO.getStockCode(),bar.getClosePrice().doubleValue(),avgPrice,amt,stockNumber);
        return positionVO;
    }

    public static BigDecimal sell(StockPositionVO positionVO,Bar bar){
        if(Objects.isNull(positionVO)){
            return BigDecimal.ZERO;
        }
        LocalDateTime date = bar.getEndTime().toLocalDateTime();
        String dateStr = DateUtil.format(date, DatePattern.NORM_DATE_FORMAT.getPattern());
        //记录开单最近的历史
        StockConstant.historyTradMap.put(positionVO.getStockCode(),positionVO);
        //卖出金额多少
        double amt = positionVO.getNumber() * bar.getClosePrice().doubleValue();
        //买出总价格-持仓市值=盈亏
        BigDecimal val = new BigDecimal(amt).subtract(positionVO.getAmt());
        log.error("## 卖出日期：{}，股票：{}，卖出价格：{}, 盈利/亏损：{}",dateStr,positionVO.getStockCode(),bar.getClosePrice().doubleValue(),val.doubleValue());
        return val;
    }

    public static BigDecimal calc(StockPositionVO positionVO,Bar bar){
        if(Objects.isNull(positionVO)){
            return BigDecimal.ZERO;
        }

        //当前价-持仓的均价
        BigDecimal sub = BigDecimal.valueOf(bar.getClosePrice().doubleValue()).subtract(positionVO.getAvgPrice());
        //8.33%
        BigDecimal upDownPercent = sub.divide(positionVO.getAvgPrice(),2,RoundingMode.HALF_UP).multiply(new BigDecimal(100));
        if(positionVO.getMaxProfitLossPercent().compareTo(BigDecimal.ZERO) == 0){
            positionVO.setMaxProfitLossPercent(upDownPercent);
        }else if(upDownPercent.compareTo(positionVO.getMaxProfitLossPercent())>0){
            positionVO.setMaxProfitLossPercent(upDownPercent);
        }

        boolean subtractBool = false;
        //账户是盈利状态，止盈回撤 -5%
        if(upDownPercent.compareTo(BigDecimal.ZERO)>0){
            subtractBool = positionVO.getMaxProfitLossPercent().subtract(upDownPercent).compareTo(positionVO.getWinPercent())>=0;
         //账户是亏损状况，-3% 止损
        }else{
            subtractBool = upDownPercent.compareTo(positionVO.getLossPercent())<=0;
        }
        positionVO.setProfitLostPercent(upDownPercent);
        //从最高收益率或亏损5%，及时止损
        if(subtractBool){
            LocalDateTime date = bar.getEndTime().toLocalDateTime();
            String dateStr = DateUtil.format(date, DatePattern.NORM_DATE_FORMAT.getPattern());
            BigDecimal valAmt = sell(positionVO,bar);
            //执行卖出动作
            log.error("## 止损日期：{}，股票：{}，卖出价格：{}, 盈利/亏损：{}",dateStr,positionVO.getStockCode(),bar.getClosePrice().doubleValue(),valAmt.doubleValue());
            System.out.println("=====================================");
            return valAmt;
        }
        return BigDecimal.ZERO;
    }
}
